/**
 * 基于对象的栈
 * 栈：栈是一种遵从后进先出（LIFO）原则的受限线性表（受限表示对结点的操作受限制）。
 * 新添加或待删除的元素保存在栈的一端，这一端叫作栈顶；另一端是最先进入或者说最旧的元素，叫栈底。
 * 例如一摞书、餐厅里的盘子、编译器和内存中保存的变量和方法等、浏览器历史记录。
 */
export default class StackObject<T> {
    private _items: any;
    private _count: number; // 栈里元素个数
    constructor() {
        this._items = {}; // 键名要求是非负整数
        this._count = 0;
    }
    /**
     * 向栈添加元素：添加一个（或几个）新元素到栈顶
     * @element 新元素
     */
    public push(element: T) {
        this._items[this._count] = element; // 用对象存储，键名用非负整数，键值是元素
        this._count ++;
    }
    /**
     * 从栈移除元素：移除栈顶的元素，同时返回被移除的元素
     */
    public pop(): T {
        if (this.isEmpty()) {
            return undefined;
        }
        this._count --;
        const result = this._items[this._count];
        delete this._items[this._count];
        return result;
    }
    /**
     * 查看栈顶元素：返回栈顶的元素，不对栈做任何的修改
     */
    public peek(): T {
        if (this.isEmpty()) {
            return undefined;
        }
        return this._items[this._count - 1];
    }
    /**
     * 查看栈大小：返回栈里的元素个数
     */
    public size(): number {
        return this._count;
    }
    /**
     * 检查栈是否为空：如果栈里没有任何元素就返回true，否则返回false
     */
    public isEmpty(): boolean {
        return this._count === 0;
    }
    /**
     * 清空栈元素：移除栈里的所有元素
     */
    public clear() {
        this._items = {};
        this._count = 0;
    }
    /**
     * 查看栈的字符串形式
     */
    public toString(): string {
        if (this.isEmpty()) {
            return '';
        }
        let objString = `${this._items[0]}`;
        for (let i = 1; i < this._count; i ++) {
            objString = `${objString},${this._items[i]}`;
        }
        return objString;
    }
}
